# 验证token的装饰器
# token_required(f)：定义一个名为 token_required 的装饰器，它接受一个函数 f 作为参数
from datetime import datetime, UTC, timedelta
from functools import wraps

import jwt
from flask import request, jsonify, current_app


def token_required(f):
    # @wraps(f)：保留原始函数(被装饰函数) f 的元信息（如函数名、文档字符串等）
    @wraps(f)
    # decorated(*args, **kwargs)：定义内部函数，它将替换被装饰的原始函数(被装饰函数)
    def decorated(*args, **kwargs):
        token = None

        # 从请求头获取token
        if 'Authorization' in request.headers:
            auth_header = request.headers['Authorization']
            # 提取token
            if auth_header.startswith('Bearer '):
                token = auth_header.split(" ")[1]

        if not token:
            return jsonify({
                "msg": "缺少token",
                "code": -1,
                "data": None
            }), 401

        try:
            # 解码token
            data = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=["HS256"])
            # 可以把解码后的数据存入g对象供视图函数使用
            current_user_id = data['id']
            current_user_account = data['account']
        except jwt.ExpiredSignatureError:
            return jsonify({
                "msg": "Token 已经过期了，请重新登录"
            }), 401
        except jwt.InvalidTokenError:
            return jsonify({
                "msg": "Token无效，请重新登录"
            }), 401

        # 调用原函数并传入解码后的用户信息
        return f(current_user_id, current_user_account, *args, **kwargs)

    # 返回内部函数 decorated，它将替换被装饰的原始函数
    return decorated

# 在每个请求中需要调用来刷新token
def token_required_with_refresh(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = None

        # 1. 尝试从 Header 获取 Token
        if 'Authorization' in request.headers:
            auth_header = request.headers['Authorization']
            if auth_header.startswith('Bearer '):
                token = auth_header.split(" ")[1]

        # 2. 如果没有 Token，直接放行（由其他装饰器检查）
        if not token:
            return f(*args, **kwargs)

        try:
            # 3. 解码 AccessToken（不验证过期时间）
            access_token_secret = current_app.config['SECRET_KEY']
            data = jwt.decode(token, access_token_secret, algorithms=["HS256"], options={'verify_exp': False})
            current_user_id = data['id']

            # 4. 检查 Token 是否即将过期（10分钟内）
            now = datetime.now(UTC).timestamp()
            if 'exp' in data and data['exp'] - now <= 600:  # 600秒 = 10分钟
                try:
                    # 5. 验证 RefreshToken
                    refresh_token_secret = current_app.config['REFRESH_TOKEN_SECRET']
                    refresh_data = jwt.decode(token, refresh_token_secret, algorithms=["HS256"])

                    # 6. 生成新 AccessToken
                    new_token = jwt.encode(
                        {
                            'id': refresh_data['id'],
                            'account': refresh_data['account'],
                            'exp': datetime.now(UTC) + timedelta(hours=24)
                        },
                        access_token_secret,
                        algorithm="HS256"
                    )

                    # 7. 调用原函数并返回新 Token（通过响应头）
                    response = f(*args, **kwargs)
                    response.headers['New-Token'] = new_token
                    return response

                except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
                    # RefreshToken 无效或过期，仍放行（由其他装饰器处理）
                    return f(*args, **kwargs)

            # Token 未临近过期，正常执行
            return f(*args, **kwargs)

        except (jwt.ExpiredSignatureError, jwt.InvalidTokenError):
            # AccessToken 无效或过期，仍放行（由其他装饰器处理）
            return f(*args, **kwargs)
    return decorated